#ifndef __COMM_HPP__
#define __COMM_HPP__
#include <iostream>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <string>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>

using namespace std;

#define PATHNAME "."  // 路径
#define PROJID 0x6666 // 项目id

const int gsize = 4096;
//共享内存特性：
//1.共享内存实际大小要向上对齐到PAGE（4kb）
//2.共享内存通信速度最快，减少了数据拷贝（系统到用户，用户到系统）
//3.共享内存没有任何保护机制（同步互斥）





// 创建key
key_t getKey()
{
    key_t key = ftok(PATHNAME, PROJID);
    if (key == -1)
    {
        cerr << "error" << errno << strerror(errno) << endl;
        exit(1);
    }
    return key;
}
// 创建共享内存shm
static int createShmHelper(key_t key, int size, int flag)
{
    int shmid = shmget(key, gsize, flag);
    if (shmid == -1)
    {
        cerr << "error" << errno << strerror(errno) << endl;
        exit(2);
    }
    return shmid;
}
// server端创建IPC_CREAT|IPC_EXCL
int creatShm(key_t key, int size)
{
    umask(0);
    return createShmHelper(key, gsize, IPC_CREAT | IPC_EXCL | 0666);
}
// client端获取 IPC_CREAT
int getShm(key_t key, int size)
{
    // umask(0);
    return createShmHelper(key, gsize, IPC_CREAT);
}

// 删除shm
void deleteShm(int shmid)
{
    int n = shmctl(shmid, IPC_RMID, nullptr);
    assert(n != -1);
    (void)n;
}
// shm关联
char *attachShm(int shmid)
{
    char *shmstart;
    shmstart = (char *)shmat(shmid, nullptr, 0);
    return shmstart;
}
// shm去关联
void detachShm(char *shmstart)
{
    int n = shmdt(shmstart);
    assert(n != -1);
    (void)n;
}

#define SERVER 0
#define CLIENT 1

class Init
{
public:
    Init(int t) : type(t)
    {
        // 创建shm 1.key 2.shmget3.关联
        key_t key = getKey();
        if (type == SERVER)
            shmid = creatShm(key, gsize);
        else
            shmid = getShm(key, gsize);
        shmstart = attachShm(shmid);
    }
    ~Init()
    {
        // 去关联
        detachShm(shmstart);
        // 如果是server删除shm
        if (type == SERVER)
        {
            deleteShm(shmid);
        }
    }
    char* getStart()
    {
        return shmstart;
    }

private:
    char *shmstart;
    int shmid;
    int type; // client or server
};

#endif
